#include "my_func.h"

//组arp包
unsigned char arp_mes[42] = {
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //目标mac
		0, 0, 0, 0, 0, 0, 					//源mac
		0x08, 0x06, 						//类型
		0x00, 0x01, 						//硬件类型,1为以太网地址
		0x08, 0x00, 						//协议类型,0800为ip类型
		0x06,								//硬件类型长度
		0x04,								//协议地址长度
		0x00, 0x01, 						//操作码类型,1为arp请求
		0, 0, 0, 0, 0, 0, 					//目标mac
		0, 0, 0, 0,							//目标ip
		0, 0, 0, 0, 0, 0,					//源mac
		0, 0, 0, 0							//源ip
		};

int find_segment(unsigned char *ip)
{
	int i = 0;
    int j = interface_count;
	for(i=0;i<j;i++){
		if(memcmp(Intf[i].ip, ip, 3)==0)//比较ip前面3个字节
			break;//相等就说明消息目标ip地址跟本机接口为相同网段,退出循环
	}
	return i;//返回接口对应的下标
}

void my_send(char *name,unsigned char *data,unsigned int data_len)
{
	struct ifreq ifr;//网络接口结构体
	struct sockaddr_ll sll;//原始套接字地址结构

    memset(&sll,0,sizeof(struct ifreq));//初始化网络接口结构体
	memset(&sll,0,sizeof(struct sockaddr_ll));//初始化原始套接字地址结构
	strncpy(ifr.ifr_name,name,IFNAMSIZ);//指定为收到消息的网卡
	ioctl(sockfd,SIOGIFINDEX,&ifr);//获取网络接口
	sll.sll_ifindex = ifr.ifr_ifindex;//将网络接口赋值给原始套接字地址结构
	sendto(sockfd,data,data_len,0,(struct sockaddr*)&sll, sizeof(sll));//发送原始包数据
}

void* mes_send(void* agv)
{
    struct mes_all mes_all_in = *(struct mes_all*)agv;
    //收到的内容转为ip头和mac头
    struct mac_hread* mac_h = (struct mac_hread*)mes_all_in.buff;
    struct ip_hread *ip_h = (struct ip_hread *)(mes_all_in.buff+14);
    //通过函数找到这个消息目的ip对应的本机接口,返回值为本机接口数组的下标
    int re_segment_num = find_segment(ip_h->dest_ip);
    if (Intf[re_segment_num].ip[2]==1)
    {
        return NULL;
    }
    
    //判断返回值,如果返回值等于接口数说明没有对应ip的接口,需要转发至其他路由器,这里先不管,直接退出
    if (re_segment_num == interface_count)return NULL;
    
    //判断这个返回值对应的接口名称,如果是lo就说明是发送给本地回环的消息,不用管,直接退出
    if (strcmp(Intf[re_segment_num].name,"lo") == 0)return NULL;
    
    //如果是广播消息,就直接退出,不转发
    if (((char*)ip_h->dest_ip)[3] == 255)return NULL;
    
    //先寻找一遍接受到消息的目的ip在本机是否有记录
    struct arp_link* re_find = arp_link_find((char*)ip_h->dest_ip);
    //没有记录就发送arp请求看能否获取到目标mac地址
    if (re_find == NULL)
    {
        struct mac_hread* mes_mac = (struct mac_hread*)arp_mes;//通过强转成结构体操作其中的数据
        struct arp_hread* mes_arp = (struct arp_hread*)(arp_mes+14);//同上
        memcpy(mes_mac->src_mac,Intf[re_segment_num].mac,6);//设置mac头的源mac
        memcpy(mes_arp->src_mac,Intf[re_segment_num].mac,6);//设置arp包里面的源mac
        memcpy(mes_arp->src_ip,Intf[re_segment_num].ip,4);//设置arp包里面的源ip
        memcpy(mes_arp->dest_ip,ip_h->dest_ip,4);//设置arp包里面的目的ip
        
        for (int i = 0; i < 5; i++)
        {
            my_send(Intf[re_segment_num].name,arp_mes,sizeof(arp_mes));//循环发送arp请求
        }
        if (re_find == NULL)
        {
            return NULL;//如果循环发送完,arp查找的返回值还没有数值,说明对方没上线,直接退出
        }
    }
    //前面条件达成说明可以转发,直接修改目的mac和源mac,直接发送
    memcpy(mac_h->dest_mac,re_find->mac,6);
    memcpy(mac_h->src_mac,Intf[re_segment_num].mac,6);
    my_send(Intf[re_segment_num].name,mes_all_in.buff,mes_all_in.buff_len);
    return NULL;
}

void* my_recv(void *agv)
{
    while (1)
    {
        unsigned char buff[buflen] = "";//存储接收到的消息
        memset(buff,0,buflen);//将buff清零
        int recv_len = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);//从sockfd接受消息
        struct mac_hread* mac = (struct mac_hread*)buff;//获取mac头
        if (ntohs(mac->type) == 0x0800)//判断类型是不是ip
        {
            //创建处理信息的线程
            struct mes_all mes_a;
            memcpy(mes_a.buff,buff,buflen);
            mes_a.buff_len = recv_len;
            pthread_t mes_thread;
            pthread_create(&mes_thread,NULL,mes_send,&mes_a);
            pthread_detach(mes_thread);
        }
        else if(ntohs(mac->type) == 0x0806)//判断类型是不是arp
        {
            //创建arp链表线程,将收到的arp包中对应主机的信息录入链表中
            pthread_t arplink_thread;
            pthread_create(&arplink_thread,NULL,get_arp_link,buff);
            pthread_detach(arplink_thread);
        }
        else if (ntohs(mac->type) == 0x0835)//判断类型是不是rarp
        {
            //占位
        }
    }

    return NULL;
}

void get_interface()
{
    //int sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));//创建原始套接字描述符

    struct ifconf ifc;//接口配置信息--interface config
    struct ifreq ifr[maxinterfaces];//请求接口信息--interface request
    
    memset(Intf,0,maxinterfaces*sizeof(struct my_interface));//初始化Intf结构体数组,因为申请的空间占不满,可能后面的空间会未初始化,需要置0

    memset(&ifc, 0, sizeof(struct ifconf));//初始化ifc
    ifc.ifc_len = maxinterfaces * sizeof(struct ifreq);//初始化ifc.len
    ifc.ifc_buf = (char *)ifr;//将ifc的指针ifc_buf指向ifr
    //通过ioctl之后会按照被初始化的ifc_len,往ifr数组中存放接口信息,ifc_len的数量不够ifr结构体长度时,就默认不再放入信息,存放完接口信息,ifc_len会被置为ifreq结构体的总长度
    ioctl(sockfd, SIOCGIFCONF, (char *)&ifc);
    
    //获取接口总数量:经过ioctl之后,ifc_len会被置为当前ifr存放数据的总长度,通过跟ifreq结构体相除获得接口的数量
    interface_count = ifc.ifc_len / (sizeof(struct ifreq));
    for (int i = 0; i < interface_count; i++)//依次将接口信息放至Intf数组里面
    {
        memcpy(Intf[i].name,ifr[i].ifr_name,sizeof(Intf[i].name));//接口名字

        //ioctl(sockfd,SIOCGIFADDR,(char *)&ifr[i]);
        memcpy(Intf[i].ip,(char *)&(((struct sockaddr_in *)&(ifr[i].ifr_addr))->sin_addr),sizeof(Intf[i].ip));//接口ip

        ioctl(sockfd, SIOCGIFFLAGS,ifr[i].ifr_name);//接口标记
        if (ifr[i].ifr_flags & IFF_UP)
            Intf[i].flag = 1;
        else 
            Intf[i].flag = 0;

        ioctl(sockfd, SIOCGIFNETMASK,(char *)&ifr[i]);//获取掩码
        memcpy(Intf[i].subnet_mask,(char *)&(((struct sockaddr_in *)&(ifr[i].ifr_addr))->sin_addr),sizeof(Intf[i].subnet_mask));

        ioctl(sockfd, SIOCGIFBRDADDR,(char *)&ifr[i]);//获取广播地址
        memcpy(Intf[i].broadcast_ip,(char *)&(((struct sockaddr_in *)&(ifr[i].ifr_addr))->sin_addr),sizeof(Intf[i].broadcast_ip));

        ioctl(sockfd, SIOCGIFHWADDR,(char *)&ifr[i]);//获取mac地址
        memcpy(Intf[i].mac,(ifr[i].ifr_hwaddr.sa_data),sizeof(Intf[i].mac));


        // char buf1[INET_ADDRSTRLEN]="";
        // inet_ntop(AF_INET,Intf[i].ip, buf1, INET_ADDRSTRLEN);
        // char buf2[INET_ADDRSTRLEN]="";
        // inet_ntop(AF_INET,Intf[i].subnet_mask, buf2, INET_ADDRSTRLEN);
        // char buf3[INET_ADDRSTRLEN]="";
        // inet_ntop(AF_INET,Intf[i].broadcast_ip, buf3, INET_ADDRSTRLEN);
        // printf("\n");
        // printf("interface:%s\n", Intf[i].name); 
        // printf("mac:%02x:%02x:%02x:%02x:%02x:%02x\n",Intf->mac[0],Intf->mac[1],Intf->mac[2],Intf->mac[3],Intf->mac[4],Intf->mac[5]);
        // printf("ip:%s\n",buf1);
        // printf("flag:%d\n",Intf[i].flag);
        // printf("subnet_mask:%s\n",buf2);
        // printf("broadcast_ip:%s\n",buf3);
        // printf("\n");
    } 
}


